package com.laozhao.dreamframe.sqlmap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//import com.laozhao.dreamframe.sqlmap.BaseSelector.Criteria;

/** 
 * @author dozhao 
 * @version create time：Aug 1, 2011 4:04:49 PM 
 * 
 */
/**
 * 查询条件
 */
public class Criteria {
	private static String CONSTANT_AND = " AND ";
	private static String CONSTANT_OR = " OR ";
	private static String CONSTANT_CONDITION = "Criteria.constant.condition";
	private static String CONSTANT_VALUE = "Criteria.constant.value";

	protected List<String> criteriaWithoutValue;

	protected List<Map<String, Object>> criteriaWithSingleValue;

	protected List<Map<String, Object>> criteriaWithListValue;

	protected List<Map<String, Object>> criteriaWithBetweenValue;

	private String logic = CONSTANT_AND;

//	public Criteria() {
//		super();
//		criteriaWithoutValue = new ArrayList<String>();
//		criteriaWithSingleValue = new ArrayList<Map<String, Object>>();
//		criteriaWithListValue = new ArrayList<Map<String, Object>>();
//		criteriaWithBetweenValue = new ArrayList<Map<String, Object>>();
//	}

	/**
	 * if logic == true return : and if logic == false return: or
	 */
	public Criteria(boolean logic) {
		super();
		if (logic) {
			this.logic = CONSTANT_AND;
		} else {
			this.logic = CONSTANT_OR;
		}
		criteriaWithoutValue = new ArrayList<String>();
		criteriaWithSingleValue = new ArrayList<Map<String, Object>>();
		criteriaWithListValue = new ArrayList<Map<String, Object>>();
		criteriaWithBetweenValue = new ArrayList<Map<String, Object>>();
	}

	public boolean isValid() {
		return criteriaWithoutValue.size() > 0
				|| criteriaWithSingleValue.size() > 0
				|| criteriaWithListValue.size() > 0
				|| criteriaWithBetweenValue.size() > 0;
	}

	// public List<String> getCriteriaWithoutValue() {
	// return criteriaWithoutValue;
	// }
	//
	// public List<Map<String, Object>> getCriteriaWithSingleValue() {
	// return criteriaWithSingleValue;
	// }
	//
	// public List<Map<String, Object>> getCriteriaWithListValue() {
	// return criteriaWithListValue;
	// }
	//
	// public List<Map<String, Object>> getCriteriaWithBetweenValue() {
	// return criteriaWithBetweenValue;
	// }

	protected void addCriterion(String condition) {
		if (condition == null || "".equals(condition)) {
			return;
		}
		criteriaWithoutValue.add(condition);
	}

	protected void addCriterion(String condition, Object value, String property) {
		if (value == null || "".equals(value)) {
			return;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(CONSTANT_CONDITION, condition);
		map.put(CONSTANT_VALUE, value);
		criteriaWithSingleValue.add(map);
	}

	protected void addCriterion(String condition,
			List<? extends Object> values, String property) {
		if (values == null || values.size() == 0) {
			return;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(CONSTANT_CONDITION, condition);
		map.put(CONSTANT_VALUE, values);
		criteriaWithListValue.add(map);
	}

	protected void addCriterion(String condition, Object value1, Object value2,
			String property) {
		if (value1 == null || value2 == null) {
			return;
		}
		List<Object> list = new ArrayList<Object>();
		list.add(value1);
		list.add(value2);
		Map<String, Object> map = new HashMap<String, Object>();
		map.put(CONSTANT_CONDITION, condition);
		map.put(CONSTANT_VALUE, list);
		criteriaWithBetweenValue.add(map);
	}

	private String quoteStr(String str) {
		if (str == null)
			return null;
		return "'" + str + "'";
	}

	String getFieldName(String field) {

		if (field == null) {
			throw new RuntimeException(field + " cannot be null");
		}
		return field.toUpperCase();
		//
		//
		// Pattern pattern = Pattern.compile("[A-Z]{1}");
		// Matcher m = pattern.matcher(field);
		// StringBuffer sbr = new StringBuffer();
		// while(m.find())
		// m.appendReplacement(sbr, "_"+m.group());
		// m.appendTail(sbr);
		// return sbr.toString().toUpperCase();
	}

	private String criteriaWithoutValueSql(StringBuffer sql, List<String> list) {
		if (list == null)
			return "";

		int n = list.size();
		for (int i = 0; i < n; i++) {
			sql.append(list.get(i));
			if (i < n - 1)
				sql.append(CONSTANT_AND);
		}

		return sql.toString();
	}

	private String criteriaWithSingleValueSql(StringBuffer sql, List<Map<String, Object>> list) {
		if (list == null)
			return "";
		if (sql.length() > 0 && list.size() > 0)
			sql.append(CONSTANT_AND);
		int n = list.size();
		for (int i = 0; i < n; i++) {
			Map<String, Object> map =  list.get(i);
			sql.append(map.get(CONSTANT_CONDITION)).append(
					map.get(CONSTANT_VALUE));
			if (i < n - 1)
				sql.append(CONSTANT_AND);
		}
		return sql.toString();
	}

	private String criteriaWithListValueSql(StringBuffer sql, List<Map<String, Object>>  list) {
		if (list == null)
			return "";
		if (sql.length() > 0 && list.size() > 0)
			sql.append(CONSTANT_AND);
		int n = list.size();
		for (int i = 0; i < n; i++) {
			Map<String, Object> map = list.get(i);
			sql.append(map.get(CONSTANT_CONDITION))
					.append(
							"("
									+ join(
											(Collection<?>) map.get(CONSTANT_VALUE), ",")
									+ ")");
			if (i < n - 1)
				sql.append(CONSTANT_AND);
		}
		return sql.toString();
	}

	private String criteriaWithBetweenValueSql(StringBuffer sql, List<Map<String, Object>>  list) {
		if (list == null)
			return "";
		if (sql.length() > 0 && list.size() > 0)
			sql.append(CONSTANT_AND);
		int n = list.size();
		for (int i = 0; i < n; i++) {
			Map<String, Object> map = list.get(i);
			sql.append(map.get(CONSTANT_CONDITION)).append(
					join((Collection<?>) map.get(CONSTANT_VALUE), CONSTANT_AND));
			if (i < n - 1)
				sql.append(CONSTANT_AND);
		}
		return sql.toString();
	}

	private String join(Collection<?> list, String spe) {
		if (list == null)
			return "";
		Object array[] = list.toArray();
		StringBuffer buff = new StringBuffer();
		for (int i = 0; i < array.length; i++) {
			buff.append(array[i]);
			if (i < array.length - 1)
				buff.append(spe);
		}
		return buff.toString();
	}

	public String getLogic() {
		return logic;
	}

	public void setLogic(boolean logic) {
		if (logic) {
			this.logic = CONSTANT_AND;
		} else {
			this.logic = CONSTANT_OR;
		}
	}

	public Criteria andIsNull(String field) {
		addCriterion(getFieldName(field) + " is null");
		return this;
	}

	public Criteria andIsNotNull(String field) {
		addCriterion(getFieldName(field) + " is not null");
		return this;
	}

	public Criteria andEqualTo(String field, String value) {
		addCriterion(getFieldName(field) + " = ", quoteStr(value), field);
		return this;
	}

	public Criteria andNotEqualTo(String field, String value) {
		addCriterion(getFieldName(field) + " <> ", quoteStr(value), field);
		return this;
	}

	public Criteria andGreaterThan(String field, String value) {
		addCriterion(getFieldName(field) + " > ", quoteStr(value), field);
		return this;
	}

	public Criteria andGreaterThanOrEqualTo(String field, String value) {
		addCriterion(getFieldName(field) + " >= ", quoteStr(value), field);
		return this;
	}

	public Criteria andLessThan(String field, String value) {
		addCriterion(getFieldName(field) + " < ", quoteStr(value), field);
		return this;
	}

	public Criteria andLessThanOrEqualTo(String field, String value) {
		addCriterion(getFieldName(field) + " <= ", quoteStr(value), field);
		return this;
	}

	public Criteria andLike(String field, String value) {
		addCriterion(getFieldName(field) + " like ", quoteStr(value), field);
		return this;
	}

	public Criteria andNotLike(String field, String value) {
		addCriterion(getFieldName(field) + " not like ", quoteStr(value), field);
		return this;
	}

	public Criteria andIn(String field, List<String> values) {
		List<String> vs = new ArrayList<String>();
		for (String string : values) {
			vs.add(quoteStr(string));
		}
		addCriterion(getFieldName(field) + " in ", vs, field);

		return this;
	}

	public Criteria andNotIn(String field, List<String> values) {
		List<String> vs = new ArrayList<String>();
		for (String string : values) {
			vs.add(quoteStr(string));
		}
		addCriterion(getFieldName(field) + " not in ", vs, field);
		return this;
	}

	public Criteria andBetween(String field, String value1, String value2) {
		addCriterion(getFieldName(field) + " between ", quoteStr(value1),
				quoteStr(value2), field);
		return this;
	}

	public Criteria andNotBetween(String field, String value1, String value2) {
		addCriterion(getFieldName(field) + " not between ", quoteStr(value1),
				quoteStr(value2), field);
		return this;
	}

	public String toSql() {

		StringBuffer sql = new StringBuffer();
		sql.append(logic);
		sql.append(" ( ");

		criteriaWithoutValueSql(sql, criteriaWithoutValue);
		criteriaWithSingleValueSql(sql, criteriaWithSingleValue);
		criteriaWithListValueSql(sql, criteriaWithListValue);
		criteriaWithBetweenValueSql(sql, criteriaWithBetweenValue);
		sql.append(" ) ");

		return sql.toString();
	}
	
}
